/**
 * 适配器模式:适配器模式可以将一个类的接口转换成客户端希望的另一个接口，使得原来由于接口不兼容而不能在一起工作的那些类可以在一起工作。通俗的讲就是当我们已经有了一些类，而这些类不能满足新的需求，此时就可以考虑是否能将现有的类适配成可以满足新需求的类。适配器类需要继承或依赖已有的类，实现想要的目标接口。
 * 适配器模式适合应用场景:
 * 1. 当使用某个类，其接口与其他代码不兼容时，可以使用适配器类。适配器模式允许创建一个中间层类，其可作为代码与遗留类、第三方类或提供怪异接口的类之间的转换器。
 * 2. 如果需要复用这样一些类，他们处于同一个继承体系，并且他们又有了额外的一些共同的方法，但是这些共同的方法不是所有在这一继承体系中的子类所具有的共性。可以扩展每个子类，将缺少的功能添加到新的子类中。但是，必须在所有新子类中重复添加这些代码，这样会使得代码有坏味道。
 * 缺点：过多地使用适配器，会让系统非常零乱，不易整体进行把握。比如，明明看到调用的是 A 接口，其实内部被适配成了 B 接口的实现，一个系统如果太多出现这种情况，无异于一场灾难。因此如果不是很有必要，可以不使用适配器，而是直接对系统进行重构。
 */
#pragma once

#include <iostream>

using namespace std;
namespace adapter
{
/*
 * 关键代码：适配器继承或依赖已有的对象，实现想要的目标接口。
 * 以下示例中，假设我们之前有了一个双端队列，新的需求要求使用栈和队列来完成。
 * 双端队列可以在头尾删减或增加元素。而栈是一种先进后出的数据结构，添加数据时添加到栈的顶部，删除数据时先删除栈顶部的数据。因此我们完全可以将一个现有的双端队列适配成一个栈。
 */

//双端队列， 被适配类
class Deque
{
public:
    void push_back(int x)
    {
        cout << "Deque push_back:" << x << endl;
    }
    void push_front(int x)
    {
        cout << "Deque push_front:" << x << endl;
    }
    void pop_back()
    {
        cout << "Deque pop_back" << endl;
    }
    void pop_front()
    {
        cout << "Deque pop_front" << endl;
    }
};

//顺序类，抽象目标类
class Sequence
{
public:
    virtual void push(int x) = 0;
    virtual void pop() = 0;
};

namespace objectmode
{
//栈,先进后出, 适配类
class Stack : public Sequence
{
public:
    //将元素添加到堆栈的顶部。
    void push(int x) override
    {
        m_deque.push_front(x);
    }
    //从堆栈中删除顶部元素
    void pop() override
    {
        m_deque.pop_front();
    }
private:
    Deque m_deque;
};

//队列，先进先出，适配类
class Queue : public Sequence
{
public:
    //将元素添加到队列尾部
    void push(int x) override
    {
        m_deque.push_back(x);
    }
    //从队列中删除顶部元素
    void pop() override
    {
        m_deque.pop_front();
    }
private:
    Deque m_deque;
};
} // namespace object

namespace classmode
{
//栈,先进后出, 适配类
class Stack : public Sequence, private Deque
{
public:
    void push(int x) override
    {
        push_front(x);
    }
    void pop() override
    {
        pop_front();
    }
};

//队列，先进先出，适配类
class Queue : public Sequence, private Deque
{
public:
    void push(int x) override
    {
        push_back(x);
    }
    void pop() override
    {
        pop_front();
    }
};
} // namespace classmode

void ClientCode()
{
    cout << "begin test object mode:" << endl;
    objectmode::Stack stack1;
    stack1.push(1);
    stack1.pop();
    objectmode::Queue queue1;
    queue1.push(1);
    queue1.pop();
    cout << "begin test class mode:" << endl;
    classmode::Stack stack2;
    stack2.push(1);
    stack2.pop();
    classmode::Queue queue2;
    queue2.push(1);
    queue2.pop();
}
} // namespace adapter
